﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Entities;
using DAL;
using System.ComponentModel.Composition;

namespace Services
{
    [Export(typeof(ISummaryService))]
    public class SummaryService :  ISummaryService
    {
        #region Member Variables

        protected readonly IAuditedOperationRepository _auditedOperationRepository;

        #endregion

        #region Constructor

        [ImportingConstructor]
        public SummaryService(IAuditedOperationRepository auditedOperationRepository)
        {
            this._auditedOperationRepository = auditedOperationRepository;
        }

        #endregion

        #region Public Methods

        public UserSummary GetUserSummary(string userAccount)
        {
            var userOperations = _auditedOperationRepository.Find(r => r.UserAccount == userAccount);
            return GetUserSummaryHelper(userAccount, userOperations);

        }

        public IEnumerable<string> GetMachineTopAccessors(string machineName)
        {
            var machines = _auditedOperationRepository.Find(m => m.ServerName == machineName);
            return (from m in machines
                    group m by m.UserAccount into grp
                    orderby grp.Count() descending
                    select grp.Key).Take(5);
        }

        public string GetDirectoryOwner(string path)
        {
            throw new NotImplementedException();
        }

        public FileSummary GetFileSummary(string fileName)
        {
            AuditedOperation[] fileOperations = _auditedOperationRepository.Find(r => r.ObjectName == fileName).OrderBy(r => r.ReceivedTime).ToArray();
            string firstAction = fileOperations[0].OperationName;
            string lastAction = fileOperations[fileOperations.Length - 1].OperationName;
            AuditedOperation firstEntry = fileOperations.Where(r => r.OperationType == (short)OperationType.Create).OrderBy(r => r.ReceivedTime).FirstOrDefault();
            DateTime? createdOn = null;
            string createdBy = null;

            if (firstEntry != null)
            {
                createdOn = firstEntry.ReceivedTime;
                createdBy = firstEntry.UserAccount;
            }

            string mostAccessedBy = fileOperations
                .Where(fo => fo.OperationType == (short)OperationType.Read || fo.OperationType == (short)OperationType.Write)
                .GroupBy(r => r.UserAccount)
                .Aggregate((a, b) => a.Count() < b.Count() ? a : b)
                .First()
                .UserAccount;

            return new FileSummary
            {
                FirstAction = firstAction,
                LastAction = lastAction,
                CreatedBy = createdBy,
                CreatedOn = createdOn,
                MostAccessedBy = mostAccessedBy
            };
        }

        #endregion

        #region Private Methods

        private string GetLastAction(IEnumerable<AuditedOperation> userOperations)
        {
            DateTime? maxDate = userOperations.ElementAt(0).ReceivedTime;
            string lastAction = userOperations.ElementAt(0).OperationName;

            foreach (var item in userOperations)
            {
                if (maxDate.HasValue && item.ReceivedTime.HasValue && maxDate.Value < item.ReceivedTime.Value)
                {
                    maxDate = item.ReceivedTime;
                    lastAction = item.OperationName;
                }
            }

            return lastAction;
        }

        private UserSummary GetUserSummaryHelper(string userAccount, IEnumerable<AuditedOperation> userOperations)
        {
            string lastAction = GetLastAction(userOperations);
            var usedMachines = (from m in userOperations
                                group m by m.ServerName into grp
                                orderby grp.Count() descending
                                select grp.Key
                               ).Take(5);
            int numberOfDeletedFiles = userOperations.Where(o => o.OperationType == (int)OperationType.Deleted).Count();

            return new UserSummary
            {
                LastAction = lastAction,
                MostUsedMachines = usedMachines,
                NumberOfFiles = numberOfDeletedFiles,
                UserName = userAccount
            };
        }

        #endregion
    }
}